Android Tips #44 Spring for Android で REST クライアントを超楽に実装する
Spring for Android とは
Spring for Android は Spring フレームワークの Android 用ライブラリです。REST クライアントを超シンプルに実装することができたので、その手順を載せたいと思います。
概要については以下も参照してください。
Spring for Android の導入
まずは以下より Spring for Android のライブラリをダウンロードします。
http://www.springsource.org/spring-android
zip ファイルを解凍し、その中の以下のファイルをプロジェクトの libs フォルダに入れます。
- libs/spring-android-auth-1.0.1.RELEASE.jar
- libs/spring-android-core-1.0.1.RELEASE.jar
- libs/spring-android-rest-template-1.0.1.RELEASE.jar
また、さらにレスポンスデータをマッピングするためのライブラリも別途必要になります。 レスポンスが XML の場合は SimpleFramework というライブラリが必要で、JSONの場合は Jackson というライブラリが必要です。 今回は両方試してみたいのでどちらもダウンロードしました。
SimpleFramework のライブラリからは以下のファイルをコピーして libs フォルダに入れます。
- jar/simple-xml-2.7.jar
Jackson のライブラリは 3 つに分かれているのですべてダウンロードして libs フォルダに入れます。
- jackson-core-2.1.4.jar
- jackson-annotations-2.1.4.jar
- jackson-databind-2.1.4.jar
レスポンスボディが XML の場合の REST 処理を実装する
まずは XML の場合です。仮に下記の XML データの Get 処理を実装して、レスポンスボディの XML データをオブジェクトにマッピングしてみましょう。
<?xml version="1.0" encoding="utf-8"?> <book> <author>Classmethod</author> <title>XmlBook</title> <price>1000</price> </book>
まずはオブジェクトクラスを作ります。SimpleFramework の記法で要素になるプロパティにアノテーションを付けていきます。
package jp.classmethod.android.sample.springforandroid; import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; @Root(name = "book") public class BookXml { @Element public String author; @Element public String title; @Element public String price; @Override public String toString() { return "author:" + author + "\ntitle:" + title + "\nprice:" + price + "\n"; } }
あとは REST 処理を実装します。 RestTemplate というクラスの RestTemplate#getMessageConverters() でレスポンスボディのデータをマッピングするインスタンスを追加します。XML の場合は SimpleXmlHttpMessageConverter を使います。あとは RestTemplate#exchange() を呼ぶと GET 処理を実行しつつレスポンスを返します。
private String getXml() { RestTemplate template = new RestTemplate(); template.getMessageConverters().add(new SimpleXmlHttpMessageConverter()); String url = "http://http://192.168.x.x/book.xml"; try { ResponseEntity<BookXml> responseEntity = template.exchange(url, HttpMethod.GET, null, BookXml.class); BookXml res = responseEntity.getBody(); return res.toString(); } catch (Exception e) { Log.d("Error", e.toString()); return null; } }
レスポンスボディが JSON の場合の REST 処理を実装する
次に JSON の場合です。仮に下記の JSON データの Get 処理を実装して、レスポンスボディの JSON データをオブジェクトにマッピングしてみましょう。
{ "author":"Classmethod", "title":"JsonBook", "price":1000 }
こちらも XML とほぼ同様の手順です。まずはオブジェクトのクラスを作ります。JSON の場合はアノテーションなどは特に必要ありません。
package jp.classmethod.android.sample.springforandroid; public class BookJson { public String author; public String title; public String price; @Override public String toString() { return "author:" + author + "\ntitle:" + title + "\nprice:" + price + "\n"; } }
あとは REST 処理の実装です。 XML の場合と異なるところは MassageConverter が MappingJackson2HttpMessageConverter になっているところくらいです。
private String getJson() { RestTemplate template = new RestTemplate(); template.getMessageConverters().add(new MappingJackson2HttpMessageConverter()); String url = "http://192.168.x.x/book.json"; try { ResponseEntity<BookJson> responseEntity = template.exchange(url, HttpMethod.GET, null, BookJson.class); BookJson res = responseEntity.getBody(); return res.toString(); } catch (Exception e) { Log.d("Error", e.toString()); return null; } }
動作させてみる
REST 処理を Activity に実装したのが以下のコードになります。「Get XML」ボタンで XML を取得し、「Get JSON」ボタンで JSON を取得します。
MainActivity.java
package jp.classmethod.android.sample.springforandroid; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.xml.SimpleXmlHttpMessageConverter; import org.springframework.web.client.RestTemplate; import android.content.Context; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.AsyncTaskLoader; import android.support.v4.content.Loader; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.TextView; public class MainActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.get_xml_button).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Bundle bundle = new Bundle(); bundle.putString("format", "xml"); getSupportLoaderManager().initLoader(0, bundle, callbacks); } }); findViewById(R.id.get_json_button).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Bundle bundle = new Bundle(); bundle.putString("format", "json"); getSupportLoaderManager().initLoader(0, bundle, callbacks); } }); } private LoaderCallbacks<String> callbacks = new LoaderCallbacks<String>() { @Override public void onLoaderReset(Loader<String> loader) { } @Override public void onLoadFinished(Loader<String> loader, String value) { getSupportLoaderManager().destroyLoader(loader.getId()); TextView v = (TextView) findViewById(R.id.result_text_view); v.setText(v.getText() + value); } @Override public Loader<String> onCreateLoader(int id, Bundle bundle) { CustomLoader loader = new CustomLoader(getApplicationContext(), bundle); loader.forceLoad(); return loader; } }; private static class CustomLoader extends AsyncTaskLoader<String> { private String mFormat; public CustomLoader(Context context, Bundle bundle) { super(context); mFormat = bundle.getString("format"); } @Override public String loadInBackground() { if (TextUtils.equals("xml", mFormat)) { return getXml(); } else { return getJson(); } } private String getXml() { RestTemplate template = new RestTemplate(); template.getMessageConverters().add(new SimpleXmlHttpMessageConverter()); String url = "http://192.168.x.x/book.xml"; try { ResponseEntity<BookXml> responseEntity = template.exchange(url, HttpMethod.GET, null, BookXml.class); BookXml res = responseEntity.getBody(); return res.toString(); } catch (Exception e) { Log.d("Error", e.toString()); return null; } } private String getJson() { RestTemplate template = new RestTemplate(); template.getMessageConverters().add(new MappingJackson2HttpMessageConverter()); String url = "http://192.168.x.x/book.json"; try { ResponseEntity<BookJson> responseEntity = template.exchange(url, HttpMethod.GET, null, BookJson.class); BookJson res = responseEntity.getBody(); return res.toString(); } catch (Exception e) { Log.d("Error", e.toString()); return null; } } } }
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <Button android:id="@+id/get_xml_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Get XML" /> <Button android:id="@+id/get_json_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/get_xml_button" android:text="Get JSON" /> <TextView android:id="@+id/result_text_view" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/get_json_button" /> </RelativeLayout>
動作させると下図のような感じになります!
サンプルソース
サンプルソースを GitHub に公開しました!ぜひ参考にしてください。
suwa-yuki/SpringForAndroidSample
まとめ
HttpURLConnection などをそのまま使うよりかなり簡単に REST のクライアントを実装できました。SimpleFramework と Jackson の紹介のようにもなってしまいましたが…これらもあわせて使うとレスポンスボディのマッピングもすごく簡単になるのでオススメです。